﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Mono.Cecil;
using Mono.Cecil.Cil;

namespace CecilILRewrite
{
    class Program
    {
        readonly MethodBody body;

        static void Main(string[] args)
        {
            var assembly = Mono.Cecil.AssemblyDefinition.ReadAssembly("MyStupidLittleConsoleApplication.exe");
            var systemAssembly = Mono.Cecil.AssemblyDefinition.ReadAssembly(typeof(Console).Assembly.Location);
            var typeDefinition = systemAssembly.MainModule.Types.Single(t => t.Name == "Console");

            //var methodDefintion = typeDefinition.Methods.Single(p => p.Name == "DoThisFirst");

            //var setMethodWriter = methodDefintion.Body.GetILProcessor();
            //setMethodWriter.InsertAfter
 
  
            var consoleType = (from s in systemAssembly.Modules[0].Types
                               where s.Name == "Console"
                               select s).Single();

            MethodReference cwm = null;

            foreach (var method in consoleType.Methods)
            {
                if (method.Name == "WriteLine")
                {
                    if (method.Parameters.Count == 1)
                    {
                        if (method.Parameters[0].ParameterType.Name == "String")
                        {
                            cwm = method;
                            break;
                        }
                    }
                }
            }

            foreach (var module in assembly.Modules)
            {
                Console.WriteLine(module.Name);

                var consoleWrite = module.Import(cwm);

                var myClassType = (from t in module.Types
                                   where t.Name == "MyClass"
                                   select t).Single();


                var voidType = new TypeReference("System", "Void", null, null);

                if (myClassType != null)
                {
                    foreach (var method in myClassType.Methods)
                    {
                        Console.WriteLine(method.Name);

                        var loadStringEntry
                            = Instruction.Create(OpCodes.Ldstr,
                                    string.Format("Calling into {0}", method.Name));

                        var loadStringExit
                            = Instruction.Create(OpCodes.Ret,
                                    string.Format("Leaving {0}", method.Name));

                        var cwInstr
                            = Instruction.Create(OpCodes.Call, consoleWrite);

                        //var setMethodWriter = methodDefintion.Body.GetILProcessor();
                        //setMethodWriter.InsertAfter(loadStringExit,

                        method.Body.Instructions.Insert(1, cwInstr);
                        method.Body.Instructions.Insert(1, loadStringEntry);
                        method.Body.Instructions.Insert(1, loadStringExit);

                        ///method.Body.Instructions.Insert 

                        foreach (var ins in method.Body.Instructions)
                        {
                            Console.WriteLine(ins);
                        }
                    }
                }
            }

            assembly.Write("new.exe");
        }
    }
}
